Skip to content

feat: String interpolation #1427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from

Conversation

developerfred
Copy link

@developerfred developerfred commented Aug 4, 2020

base #1115
close near/near-sdk-as#201

  • merge
  • update test

@developerfred developerfred force-pushed the issue/201 branch 2 times, most recently from ff3d722 to 7508daa Compare August 4, 2020 19:14
@pulpdrew
Copy link
Contributor

pulpdrew commented Aug 5, 2020

I was also working on this, before realizing that someone else was. I'll leave it to you, but here are some test cases I came up with while testing my implementation, just in case they're helpful:

tests/parser/literals.ts:

``;
`123`;
`$1`;
`$ {}`;
`} {`;
`${foo}`;
`${foo}${foo}`;
`1${foo() + 1}`;
`${2 - 1}2`;
`12${3}45`;
`\${} ${foo}`;
`1${`2${3}`}`;
`foo:

${foo}`;
`${}` // Error

tests/parser/literals.fixture.ts (these will probably differ for your implementation)

"123";
"1\"23";
"1\"2\\3";
"\0\n\\n\r";
"";
"123";
"$1";
"$ {}";
"} {";
(foo).toString();
(foo).toString() + (foo).toString();
"1" + (foo() + 1).toString();
(2 - 1).toString() + "2";
"12" + (3).toString() + "45";
"${} " + (foo).toString();
"1" + ("2" + (3).toString()).toString();
"foo:\n\n" + (foo).toString();
"" // Should write out an error, too

@MaxGraey
Copy link
Member

MaxGraey commented Aug 8, 2020

Btw will be great if you avoid using String#concat here and use joinStringArray instead when count of arguments more than 2

@developerfred
Copy link
Author

Btw will be great if you avoid using String#concat here and use joinStringArray instead when count of arguments more than 2

thanks, my return parts look like this

return parts.reduce((acc: Expression | null, expr: Expression) => {
      if (acc == null) return expr;
      return Node.createTemplateLiteralExpression(joinStringArray(expr), tn.range(startPos, tn.pos));
    }, null);

@MaxGraey
Copy link
Member

MaxGraey commented Aug 9, 2020

I guess it should be (in pseudocode):

if (parts.lenght == 0) return <empty string>;
else if (parts.lenght == 1) {
  return isStringExpression(parts[0]) 
     ? parts[0] 
     : makeCallExpression('toString', parts[0]) // stringify if needed
} else if (parts.lenght == 2) {
  return Node.createBinaryExpression(Token.PLUS, parts[0], parts[1], tn.range(startPos, tn.pos));
} else if (parts.lenght == 3) {
  // optional for this PR but will be great
  // depends on pr #1432  
  return makeCallExpression('joinThreeStrings', parts[0], parts[1], parts[2]);
} else {
  return makeCallExpression('joinStringArray', makeArrayExpression(parts));
}

@MaxGraey MaxGraey mentioned this pull request Aug 9, 2020
1 task
@developerfred
Copy link
Author

developerfred commented Aug 9, 2020

@MaxGraey According to the pseudocode

  • isStringExpression(expr: any): boolean

  • makeCallExpression(callExpression: string , ...args:any)

  • function makeArrayExpression(parts: any)

    // isStringExpression checks if the string is an Expression
    function isStringExpression(expr: any): boolean {
      return (expr instanceof Expression) ? true : false
    };
    // makeCallExpression calls an expression according to the function
    function makeCallExpression(callExpression: string , ...args:any) {
      switch (callExpression) {
        case 'toString':
          return (typeof args == 'object') ? JSON.stringify(args) : args.toString()
          break;
        case 'joinThreeStrings':
          return joinThreeStrings(args[0], args[1], args[2]);
          break;    
        case 'joinStringArray':
          return joinStringArray(args);
          break;          
      }
function makeArrayExpression(parts: any) {
      return {
        type: "ArrayExpression",
        dataStart: parts[0],
        length: parts[1],
        separator: parts[2]
      };
    }

@MaxGraey
Copy link
Member

MaxGraey commented Aug 9, 2020

No, this will much more complicated. I guess @dcodeIO will assist better than me how to implement such routines

@dcodeIO
Copy link
Member

dcodeIO commented Aug 9, 2020

To emit a call to a standard library function, one would obtain a reference to it from the program, resolve it and create a direct call:

let prototype = program.require("~lib/file/concat3", ElementKind.FUNCTION_PROTOTYPE);
let instance = assert(resolver.resolveFunction(<FunctionPrototype>prototype, null)); // here: not generic
let expr = compiler.makeCallDirect(instance, [arg1, arg2, arg3], reportNode, immediatelyDropped?, skipAutorelease?);

emitting about

(call $~lib/file/concat3
 (arg1)
 (arg2)
 (arg3)
)

@developerfred
Copy link
Author

@dcodeIO Thank you so much!

@MaxGraey
Copy link
Member

MaxGraey commented Aug 1, 2021

Already implemented in #1715. Closing

@MaxGraey MaxGraey closed this Aug 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bounty] Add String Interpolation to AssemblyScript
4 participants